//==========================================================================
// Copyright (c) 2000-2008,  Elastos, Inc.  All Rights Reserved.
//==========================================================================
#include "namedcondition.h"
#include "cthread.h"
#include "pseudo.h"
#include "pcentral.h"
#include "helper.h"
#include <aura.h>

#undef Lock
#undef Unlock

CNamedCondition::~CNamedCondition()
{
    if (NULL != m_pName) {
        WStringBuf::Free(m_pName);
        m_pName = NULL;
    }
}

ECode CNamedCondition::Initialize(
    /* [in] */ WString name)
{
    Int32 length = name.GetLength(AURA_MAX_PATH) + 1;
    assert(!name.IsNullOrEmpty());

    m_pName = WStringBuf::Alloc(length);
    if (NULL == m_pName) {
        return E_OUT_OF_MEMORY;
    }
    m_pName->Copy(name);

    return NOERROR;
}

PInterface CNamedCondition::Probe(
    /* [in ] */ REIID riid)
{
    if (riid == EIID_IInterface) {
        return (PInterface)(ICondition *)this;
    }
    else if (riid == EIID_ICondition) {
        return (ICondition *)this;
    }
    else if (riid == EIID_CLASS_INFO) {
        return (PInterface)&ECLSID_CCondition;
    }
    else if (riid == EIID_INTERFACE_INFO) {
        return (PInterface)&EIID_ICondition;
    }

    return NULL;
}

UInt32 CNamedCondition::AddRef()
{
    Int32 nRef = m_cRef.Increment();
    return (UInt32)nRef;
}

UInt32 CNamedCondition::Release()
{
    Int32 nRef = m_cRef.Decrement();
    if (nRef == 0) {
        CNamedConditionFactory factory(*m_pName);
        NamedObject::S_DestroyObject(&factory, m_oid);
        delete this;
    }
    return (UInt32)nRef;
}

ECode CNamedCondition::Aggregate(
    /* [in]  */ AggrType type,
    /* [in]  */ PInterface pObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CNamedCondition::GetDomain(
    /* [out] */ PInterface * ppObj)
{
    return E_NOT_IMPLEMENTED;
}

ECode CNamedCondition::Wait(
    /* [in] */ IMutex * pMutex,
    /* [out] */ WaitResult * pResult)
{
    if ((NULL == pMutex)
        || (NULL == pResult)) {
        return E_INVALID_ARGUMENT;
    }

    return this->TryWait(pMutex, INFINITE, pResult);
}

ECode CNamedCondition::TryWait(
    /* [in] */ IMutex * pMutex,
    /* [in] */ Millisecond32 msTimeout,
    /* [out] */ WaitResult * pResult)
{
    WaitResult wr;
    ECode ec = NOERROR;

    if ((NULL == pMutex)
        || (NULL == pResult)
        || ((msTimeout <= 0) && (INFINITE != msTimeout))) {
        return E_INVALID_ARGUMENT;
    }

    THREAD_START_SLEEP_NAMED()
    {
        pMutex->Unlock();
        ec = CPseudoCentral::Condition_Wait(m_oid, msTimeout, pResult);
        pMutex->Lock(&wr);
    }
    THREAD_END_SLEEP_NAMED;

    return ec;
}

ECode CNamedCondition::Pulse()
{
    return CPseudoCentral::Condition_Pulse(m_oid);
}

ECode CNamedCondition::PulseAll()
{
    return CPseudoCentral::Condition_PulseAll(m_oid);
}


ECode CNamedConditionFactory::CreateNamedObject(
            /* [out] */ NamedObject ** ppNamedObj,
            /* [out] */ Boolean * pbAlreadyExisted)
{
    CNamedCondition * pCondition = NULL;
    ECode ec = NOERROR;
    oid_t oid = 0;

    assert(NULL != ppNamedObj);
    assert(NULL != pbAlreadyExisted);

    ec = CPseudoCentral::Condition_Create(m_name, pbAlreadyExisted, &oid);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    pCondition = new CNamedCondition(oid);
    if (NULL == pCondition) {
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }
    ec = pCondition->Initialize(m_name);
    if (FAILED(ec)) {
        goto ErrorExit;
    }
    pCondition->AddRef();
    *ppNamedObj = pCondition;

    return ec;

ErrorExit:
    if (NULL != pCondition) {
        delete pCondition;
    }
    if (oid > 0) {
        CPseudoCentral::ReleaseNamedObject(oid);
    }
    return ec;
}

ECode CNamedConditionFactory::ResolveNamedObject(
            /* [in]  */ oid_t oid,
            /* [out] */ NamedObject ** ppNamedObj)
{
    CNamedCondition * pCondition = NULL;
    ECode ec = NOERROR;

    assert(NULL != ppNamedObj);

    pCondition = new CNamedCondition(oid);
    if (NULL == pCondition) {
        ec = E_OUT_OF_MEMORY;
        goto ErrorExit;
    }
    ec = pCondition->Initialize(m_name);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    ec = CPseudoCentral::AddRefNamedObject(oid);
    if (FAILED(ec)) {
        goto ErrorExit;
    }

    pCondition->AddRef();
    *ppNamedObj = pCondition;

    return ec;

ErrorExit:
    if (NULL != pCondition) {
        delete pCondition;
    }
    return ec;
}

ECode CNamedConditionFactory::DestroyNamedObject(
            /* [in]  */ oid_t oid)
{
    return CPseudoCentral::ReleaseNamedObject(oid);
}

